using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.WowAddonStudio.Services;

using IServiceProvider=System.IServiceProvider;

namespace Microsoft.WowAddonStudio.Lua.RuntimeService.ToolWindows
{
	/// <summary>
	/// Class that implements the tool window exposed by this package and hosts a user control.
	/// </summary>
	[ComVisible(true)]
	[Guid(GuidStrings.WoWBenchToolWindow)]
	public class WowBenchToolWindow : ToolWindowPane, IOleComponent
	{
		private IToolWindowControl control;

		/// <summary>
		/// Initializes a new instance of the <see cref="WowBenchToolWindow"/> class.
		/// </summary>
		public WowBenchToolWindow()
			: this(null)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="WowBenchToolWindow"/> class.
		/// </summary>
		/// <param name="provider"></param>
		public WowBenchToolWindow(IServiceProvider provider) : base(provider)
		{
			Caption = Resources.WoWBenchToolWindowTitle;
		}

		/// <summary>
		/// Initialize WoWBenchToolWindow.
		/// </summary>
		protected override void Initialize()
		{
			base.Initialize();

			var runtimeService = (LuaRuntimeService) GetService(typeof (ILuaRuntimeService));
			ILuaRuntime runtime = runtimeService.LuaRuntime;

			control = runtime.ToolWindowControl;
		}

		/// <summary>
		/// Gets the handle to the user control hosted in the Tool Window.
		/// </summary>
		/// <returns>An IWin32Window object.</returns>
		public override IWin32Window Window
		{
			get { return control; }
		}

		#region IOleComponent Members

		// Any component that needs idle time, the ability to process
		// messages before they are translated (for example, to call TranslateAccelerator 
		// or IsDialogMessage), notification about modal states, or the ability to push message 
		// loops must implement this interface and register with the Component Manager.

		/// <summary>
		/// Called during each iteration of a message loop that the component pushed.
		/// </summary>
		/// <param name="uReason">The reason for the call.</param>
		/// <param name="pvLoopData">The component's private data.</param>
		/// <param name="pMsgPeeked">The peeked message, or NULL if no message is in the queue.</param>
		/// <returns>
		/// TRUE (not zero) if the message loop should continue, otherwise FALSE (zero).
		/// If false is returned, the component manager terminates the loop without
		/// removing pMsgPeeked from the queue.
		/// </returns>
		/// <remarks>
		/// This method is called after peeking the next message in the queue (via PeekMessage)
		/// but before the message is removed from the queue.  This method may be additionally 
		/// called when the next message has already been removed from the queue, in which case
		/// pMsgPeeked is passed as NULL.
		/// </remarks>
		public int FContinueMessageLoop(uint uReason, IntPtr pvLoopData, MSG[] pMsgPeeked)
		{
			throw new NotImplementedException("The method or operation is not implemented.");
		}

		/// <summary>
		/// Called when the Visual Studio IDE goes idle to give 
		/// the component a chance to perform idle time tasks.  
		/// </summary>
		/// <param name="grfidlef">
		/// A group of bit flags taken from the enumeration of oleidlef values,
		/// indicating the type of idle tasks to perform.  
		/// </param>
		/// <returns>
		/// TRUE (not zero) if more time is needed to perform the idle time tasks, otherwise FALSE (zero).
		/// </returns>
		/// <remarks>
		/// The component may periodically call FContinueIdle and, if it returns
		/// false, the component should terminate its idle time processing and return.  
		/// If a component reaches a point where it has no idle tasks and does not need
		/// FDoIdle calls, it should remove its idle task registration via 
		/// FUpdateComponentRegistration.  If this method is called while the component
		/// is performing a tracking operation, the component should only perform idle time 
		/// tasks that it deems appropriate to perform during tracking.
		/// </remarks>
		public int FDoIdle(uint grfidlef)
		{
			return 0;
		}

		/// <summary>
		/// Gives the component a chance to process the message before it is translated and dispatched.
		/// </summary>
		/// <param name="pMsg">The message to process.</param>
		/// <returns>TRUE (not zero) if the message is consumed, otherwise FALSE (zero).</returns>
		/// <remarks>
		/// The component can do TranslateAccelerator, do IsDialogMessage, modify pMsg, or take some other action.
		/// </remarks>
		public int FPreTranslateMessage(MSG[] pMsg)
		{
			return 0;
		}

		/// <summary>
		/// Called when component manager wishes to know if the 
		/// component is in a state where it can terminate.
		/// </summary>
		/// <param name="fPromptUser">
		/// TRUE (not zero) to prompt the user for permission to terminate, otherwise FALSE (zero).
		/// </param>
		/// <returns>TRUE (not zero) if okay to terminate, otherwise FALSE (zero).</returns>
		/// <remarks>
		/// If fPromptUser is false, the component should simply return true if 
		/// it can terminate or false otherwise.
		/// If fPromptUser is true, the component should return true if it can
		/// terminate without prompting the user; otherwise, it should prompt the
		/// user by either (a) asking the user if it can terminate and returning true
		/// or false appropriately, or (b) giving an indication as to why it cannot 
		/// terminate and returning false.
		/// </remarks>
		public int FQueryTerminate(int fPromptUser)
		{
			return 1;
		}

		/// <summary>
		/// A reserved method; must return TRUE (not zero).
		/// </summary>
		public int FReserved1(uint dwReserved, uint message, IntPtr wParam, IntPtr lParam)
		{
			return 1;
		}

		/// <summary>
		/// Retrieves a window associated with the component.
		/// </summary>
		/// <param name="dwReserved">Reserved for future use and should be zero.</param>
		/// <param name="dwWhich">An value from the olecWindow enumeration.</param>
		/// <returns>The desired window or NULL if no such window exists.</returns>
		public IntPtr HwndGetWindow(uint dwWhich, uint dwReserved)
		{
			return Window.Handle;
		}

		/// <summary>
		/// Notifies the component when a new object is being activated.
		/// </summary>
		/// <param name="dwReserved">Reserved for future use.</param>
		/// <param name="fHostIsActivating">TRUE (not zero) if the host is the object being activated, otherwise FALSE (zero).</param>
		/// <param name="fSameComponent">TRUE (not zero) if pic is the same component as the callee of this method, otherwise FALSE (zero).</param>
		/// <param name="pchostinfo">An OLECHOSTINFO that contains information about the host.</param>
		/// <param name="pcrinfo">An OLECRINFO that contains information about pic.</param>
		/// <param name="pic">The IOleComponent object to activate.</param>
		/// <remarks>
		/// If pic is non-NULL, then it is the component that is being activated.
		/// In this case, fSameComponent is true if pic is the same component as
		/// the callee of this method, and pcrinfo is the information about the pic.
		/// If pic is NULL and fHostIsActivating is true, then the host is the
		/// object being activated, and pchostinfo is its host info.
		/// If pic is NULL and fHostIsActivating is false, then there is no current
		/// active object.
		/// If pic is being activated and pcrinfo->grf has the olecrfExclusiveBorderSpace 
		/// bit set, the component should hide its border space tools (toolbars, 
		/// status bars, etc.), and it should also do this if the host is activating and 
		/// pchostinfo->grfchostf has the olechostfExclusiveBorderSpace bit set.
		/// In either of these cases, the component should unhide its border space
		/// tools the next time it is activated.
		/// If pic is being activated and pcrinfo->grf has the olecrfExclusiveActivation
		/// bit is set, then pic is being activated in 'ExclusiveActive' mode.  The
		/// component should retrieve the top frame window that is hosting pic
		/// (via pic->HwndGetWindow(olecWindowFrameToplevel, 0)).  
		/// If this window is different from the component's own top frame window, 
		/// the component should disable its windows and do the things it would do
		/// when receiving an OnEnterState(olecstateModal, true) notification. 
		/// Otherwise, if the component is top-level, it should refuse to have its window 
		/// activated by appropriately processing WM_MOUSEACTIVATE.
		/// The component should remain in one of these states until the 
		/// ExclusiveActive mode ends, indicated by a future call to OnActivationChange 
		/// with the ExclusiveActivation bit not set or with a NULL pcrinfo.
		/// </remarks>
		public void OnActivationChange(IOleComponent pic, int fSameComponent, OLECRINFO[] pcrinfo, int fHostIsActivating,
		                               OLECHOSTINFO[] pchostinfo, uint dwReserved)
		{
		}

		/// <summary>
		/// Notifies the component when the host application gains or loses activation.
		/// </summary>
		/// <param name="dwOtherThreadID">The ID of the thread that owns the window.</param>
		/// <param name="fActive">TRUE (not zero) if the host application is being activated, otherwise FALSE (zero).</param>
		/// <remarks>
		/// If fActive is TRUE, the host application is being activated and
		/// dwOtherThreadID is the ID of the thread owning the window being deactivated.
		/// If fActive is false, the host application is being deactivated and 
		/// dwOtherThreadID is the ID of the thread owning the window being activated.
		/// This method is not called when both the window being activated
		/// and the window being deactivated belong to the host application.
		/// </remarks>
		public void OnAppActivate(int fActive, uint dwOtherThreadID)
		{
		}

		/// <summary>
		/// Notifies the component when the application enters or exits (as indicated by fEnter).
		/// </summary>
		/// <param name="fEnter">TRUE (not zero) for enter and FALSE (zero) for exit.</param>
		/// <param name="uStateID">The state identifier from the olecstate enumeration.</param>
		/// <remarks>
		/// If n calls are made with a true fEnter, the component should consider 
		/// the state to be in effect until n calls are made with a false fEnter.
		/// The component should be aware that it is possible for this method to
		/// be called with a false fEnter more times than it was called with a true
		/// fEnter.  For example, if the component is maintaining a state counter
		/// incremented when this method is called with a true fEnter and decremented
		/// when called with a false fEnter, then the counter should not be decremented
		/// for a false fEnter if it is already at zero.
		/// </remarks>
		public void OnEnterState(uint uStateID, int fEnter)
		{
		}

		/// <summary>
		/// Notifies the active component that it has lost its active status
		/// because the host or another component has become active.
		/// </summary>
		public void OnLoseActivation()
		{
		}

		/// <summary>
		/// Called when the component manager wishes to terminate the component's registration.
		/// </summary>
		/// <remarks>
		/// The component should revoke its registration with the component manager,
		/// release references to component manager and perform any necessary cleanup.
		/// </remarks>
		public void Terminate()
		{
		}

		#endregion IOleComponent Members
	}
}